﻿#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

//题目名称：
//统计二进制中比特位为1的个数
//题目内容：
//写一个函数返回参数二进制中 1 的个数。
//
//比如： 15    0000 1111    4 个 1
#if 0
int main() {
	int a = 0;
	scanf("%d", &a);

	int total = 0;
	for (int i = 0; i < 32; i++) {
		if (((a >> i) & 1) == 1) {
			total++;
		}
	}
	printf("%d\n", total);
	return 0;
}
#endif


//题目名称：
//交换两个变量（不创建临时变量）
//题目内容：
//不允许创建临时变量，交换两个整数的内容

#if 0
int main() {
	int a = 10;
	int b = 20;

	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a = %d, b = %d\n", a, b);
	return 0;
}
#endif

#if 0
int main()
{
	int a = 0x11223344;
	char* pc = (char*)&a;
	*pc = 0;
	printf("%x\n", a);
	return 0;
}
#endif

//题目名称：
//使用指针打印数组内容
//题目内容：
//写一个函数打印arr数组的内容，不使用数组下标，使用指针。
//
//arr是一个整形一维数组。

#if 0
int func(int arr[], int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", *(arr + i));
	}
}

int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	func(arr, 10);

	return 0;
}
#endif

//题目名称：
//字符串逆序
//题目内容：
//写一个函数，可以逆序一个字符串的内容。

#if 0
void reverse(char* str) {
	int left = 0;
	int right = strlen(str) - 1;
	while (left < right) {
		char tmp = *(str+left);
		*(str + left) = *(str + right);
		*(str + right) = tmp;
		left++;
		right--;
	}
}

int main() {
	char arr[] = "abcdef";
	reverse(arr);

	printf("%s\n", arr);
	return 0;
}
#endif


//题目名称：
//计算求和
//题目内容：
//求Sn = a + aa + aaa + aaaa + aaaaa的前5项之和，其中a是一个数字，
//例如：2 + 22 + 222 + 2222 + 22222   24690

//f（n） = f(n - 1) * 10 + a

#if 0
int main() {
	int a, n;
	scanf("%d %d", &a, &n);
	//总和
	int total = 0;
	//每一项
	int tmp = 0;

	//求出表达式当中的每一项， 在累加求和
	for (int i = 0; i < n; i++) {
		tmp = tmp * 10 + a;
		total += tmp;
	}
	printf("%d\n", total);
	return 0;
}
#endif


//题目名称：
//打印水仙花数
//题目内容：
//求出0～100000之间的所有“水仙花数”并输出。
//
//“水仙花数”是指一个n位数，其各位数字的n次方之和确好等于该数本身，
//如 : 153＝1 ^ 3＋5 ^ 3＋3 ^ 3，则153是一个“水仙花数”。

#if 0
#include <math.h>
//153
void func(int num) {
	//1.求num是多少位数字
	int count = 0;
	int tmp = num;
	while (tmp) {
		tmp /= 10;  
		count++;
	}
	tmp = num;
	//求num每一位数字的n次方的时候
	//153
	int total = 0;
	while (tmp) {
		total += pow(tmp % 10, count);
		tmp /= 10; 
	}

	//3.判断是否是水仙花数
	if (num == total) {
		printf("%d ", num);
	}
}

int main() {
	//i => [0, 100000]
	for (int i = 0; i <= 100000; i++) {
		func(i);
	}
	printf("\n");
	return 0;
}
#endif


//题目名称：
//打印菱形
//题目内容：
//用C语言在屏幕上输出以下图案
#if 0
int main() {

	//n代表菱形的上半部分的行数
	int n;
	scanf("%d", &n);
	//打印菱形上半区的内容， 策略是一行一行打印， 一行当中分为两个部分
	for (int i = 0; i < n; i++) {
		//1.空格部分
		for (int j = 0; j < n - i - 1; j++) {
			printf(" ");
		}
		//2.*号部分
		for (int j = 0; j < 2 * i + 1; j++) {
			printf("*");
		}
		printf("\n");
	}

	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j <= i ; j++) {
			printf(" ");
		}
		//for (int z = 0; z < (6 - i) * 2 - 1; z++) {
		//	printf("*");
		//}
		for (int j = 0; j < 2 * (n - i - 1) - 1; j++) {
			printf("*");
		}
		printf("\n");

	}
	return 0;
}
#endif

#if 0
struct stu
{
	int num;
	char name[10];
	int age;
};


void fun(struct stu* p)
{
	printf("%s\n", (*p).name);
	return;
}

int main()
{
	struct stu students[3] = { {9801,"zhang",20},
							  {9802,"wang",19},
							  {9803,"zhao",18}
	};
	fun(students + 1);
	return 0;
}

struct S
{
	int a;
	int b;
};
int main()
{
	struct S a, *p = &a;
	a.a = 99;
	printf("%d\n", (*p).a);
	return 0;
}
#endif

//题目名称：
//喝汽水问题
//题目内容：
//喝汽水，1瓶汽水1元，2个空瓶可以换一瓶汽水，给20元，可以喝多少汽水（编程实现）。

#if 0
int main() {
	int money = 20;
	//能喝多少
	int total = money;
	//有多少个空瓶子
	int empty = money;

	while (empty > 1) {
		//继续喝， 继续计算
		total += empty / 2;
		//重新计算目前手中有多少空瓶子
		empty = empty / 2 + empty % 2;
	}
	printf("%d\n", total);
	return 0;
}
#endif


//题目名称：
//杨辉三角
//题目内容：
//在屏幕上打印杨辉三角。
//1
//1 1
//1 2 1
//1 3 3 1
//……

#if 0
int main() {
	//需要注意这种初始化方式是将第一行第一列的元素初始化位1， 其余都是0
	int arr[30][30] = { 1 };
	for (int i = 1; i < 5; i++) {
		arr[i][0] = 1;
		for (int j = 1; j <= i; j++) {
			arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
		}
	}

	for (int i = 0; i < 5; i++) {
		for (int j = 0; j <= i; j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}
#endif

#if 0
#include <stdlib.h>
int main() {

	int row_and_col;
	scanf("%d", &row_and_col);
	int** arr = (int**)malloc(sizeof(int*) * row_and_col);
	for (int i = 0; i < row_and_col; i++) {
		arr[i] = (int*)malloc(sizeof(int) * row_and_col);
	}

	//需要注意进行初始化
	for (int i = 0; i < row_and_col; i++) {
		for (int j = 0; j < row_and_col; j++) {
			arr[i][j] = 0;
		}
	}

	arr[0][0] = 1;
	for (int i = 1; i < row_and_col; i++) {
		arr[i][0] = 1;
		for (int j = 1; j <= i; j++) {
			arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
		}
	}

	for (int i = 0; i < row_and_col; i++) {
		for (int j = 0; j <= i; j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}

	for (int i = 0; i < row_and_col; i++) {
		free(arr[i]);
	}
	
	free(arr);
	return 0;
}
#endif

//题目名称：
//猜凶手
//题目内容：
//日本某地发生了一件谋杀案，警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
//以下为4个嫌疑犯的供词:
//A说：不是我。
//B说：是C。
//C说：是D。
//D说：C在胡说
//已知3个人说了真话，1个人说的是假话。
//现在请根据这些信息，写一个程序来确定到底谁是凶手。

/*
面对这个题， 我们可以用程序的真假来表示
用假设法来验证
*/

#if 0
int main() {
	//初始化arr数组， 4个元素， 分别代表4个人， 为0表示不是凶手， 为1表示是凶手
	//先初始化4个人都是不是凶手， 然后轮流假设4个人是凶手， 根据条件去判断
	int arr[4] = { 0 };
	int i = 0;
	for (; i < 4; i++) {
		//轮流假设 某人是凶手
		arr[i] = 1;
		if (((arr[0] != 1) + 
			(arr[2] == 1) + 
			(arr[3] == 1) + 
			(arr[3] != 1)) == 3) {
			break;
		}
		//如果走到这里了， 说明刚才的arr[i]这个人不是凶手， 所以在置为0
		arr[i] = 0;
	}
	printf("%c\n", ('A' + i));

	return 0;
}
#endif


//题目名称：
//猜名次
//题目内容：
//5位运动员参加了10米台跳水比赛，有人让他们预测比赛结果：
//A选手说：B第二，我第三；
//B选手说：我第二，E第四；
//C选手说：我第一，D第二；
//D选手说：C最后，我第三；
//E选手说：我第四，A第一；
//比赛结束后，每位选手都说对了一半，请编程确定比赛的名次。


#if 0
int main() {
	//分别列举 A/B/C/D/E 选手为 1/2/3/4/5的情况， 在根据条件判断
	for (int A = 1; A <= 5; A++) {
		for (int B = 1; B <= 5; B++) {
			for (int C = 1; C <= 5; C++) {
				for (int D = 1; D <= 5; D++) {
					for (int E = 1; E <= 5; E++) {
						if (
							((B == 2) + (A == 3) == 1) &&
							((B == 2) + (E == 4) == 1) &&
							((C == 1) + (D == 2) == 1) &&
							((C == 5) + (D == 3) == 1) &&
							((E == 4) + (A == 1) == 1) &&
							(A*B*C*D*E == 120)
							) {
							printf("A=%d B=%d C=%d D=%d E=%d\n",
								A, B, C, D, E);
						}
					}
				}
			}
		}
	}
	return 0;
}
#endif

//题目名称：
//字符串旋转结果
//题目内容：
//写一个函数，判断一个字符串是否为另外一个字符串旋转之后的字符串。
//
//例如：给定s1 = AABCD和s2 = BCDAA，返回1
//给定s1 = abcd和s2 = ACBD，返回0.
//
//AABCD左旋一个字符得到ABCDA
//AABCD左旋两个字符得到BCDAA
//AABCD右旋一个字符得到DAABC

#if 0
int findRound(const char* src, char* find)
{
	//用一个辅助空间将原字符串做成两倍原字符串
	char tmp[201] = { 0 }; 
	//先拷贝一遍
	strcpy(tmp, src); 
	//再连接一遍
	strcat(tmp, src); 

	return strstr(tmp, find) != NULL; //看看找不找得到
}

int main() {
	char s1[100] = { 0 }, s2[100] = { 0 };
	scanf("%s %s", s1, s2);
	printf("%d\n", findRound(s1, s2));
	return 0;
}
#endif

#if 0
void Reverse(char* str, int size) {
	int left = 0; 
	int right = size - 1;
	while (left < right) {
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		left++;
		right--;
	}
}

void Laevorotat(char* str, int n) {
	int str_len = strlen(str);
	Reverse(str, n);
	//abcdef 1

	Reverse(str + n, str_len - n);
	Reverse(str, str_len);
}

int main() {
	char s1[100] = { 0 }, s2[100] = { 0 };
	scanf("%s %s", s1, s2);

	int s1_len = strlen(s1);
	int s2_len = strlen(s2);
	if (s1_len != s2_len) {
		printf("0");
		return 0;
	}

	for (int i = 0; i < s1_len; i++) {
		Laevorotat(s1, i);
		if (strcmp(s1, s2) == 0) {
			printf("1");
			return 1;
		}
	}
	printf("0");

	return 0;
}
#endif

//题目名称：
//杨氏矩阵
//题目内容：
//有一个数字矩阵，矩阵的每行从左到右是递增的，矩阵从上到下是递增的，
//请编写程序在这样的矩阵中查找某个数字是否存在。
//
//要求：时间复杂度小于O(N);


/*

由于杨氏矩阵的特点决定了针对表中的任一元素，
下方和右方的数据一定大于我，
左方和上方的数据一定小于我，
所以查找的时候可以利用这一特点，
从左上或者右下角来找。
因为这两个位置的大于小于是有区分度的。
例如我选择从左上角找，那么没有上边和右边，
所以下边一定比我大，左边一定比我小，
那么要查找的数字如果比我大，那我就向下，如果比我小，那我就向左，
这样查找的次数只有x+y-1次，符合题目中要求的O(n)。
*/




/*
1 2 3 4 5 6 7  8
2 3 4 5 6 7 8  9
3 4 5 6 7 8 9  10
4 5 6 7 8 9 10 11
*/

#if 0
int findnum(int a[][3], int x, int y, int f) 
{
	//从右上角开始遍历
	int i = 0, j = y - 1; 

	while (j >= 0 && i < x){
		//比我大就向下
		if (a[i][j] < f) {
			i++;
		} else if (a[i][j] > f) {
			//比我小就向左
			j--;
		}else{
			return 1;
		}
	}
	return 0;
}

int main()
{
	int a[][3] = { {1, 3, 5},
				  {3, 5, 7},
				  {5, 7, 9} }; //一个示例

	if (findnum(a, 3, 3, 9)){
		printf("It has been found!\n");
	} else {
		printf("It hasn't been found!\n");
	}
	return 0;
}
#endif


//模拟实现memmove
#if 0
void* memmove(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	if (dst <= src || (char*)dst >= ((char*)src + count)) {
		/*
		* Non-Overlapping Buffers
		* copy from lower addresses to higher addresses
		*/
		while (count--) {
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else {
		/*
		* Overlapping Buffers
		* copy from higher addresses to lower addresses
		*/
		dst = (char*)dst + count - 1;
		src = (char*)src + count - 1;
		​
		while (count--) {
			*(char*)dst = *(char*)src;
			dst = (char*)dst - 1;
			src = (char*)src - 1;
		}
	}
	return(ret);
}
#endif
/*
有效对其值：是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。
有效对齐值也叫对齐单位。

了解了上面的概念后，我们现在可以来看看内存对齐需要遵循的规则：

(1) 结构体第一个成员的偏移量（offset）为0，
以后每个成员相对于结构体首地址的 offset 
都是该成员大小与有效对齐值中较小那个的整数倍
，如有需要编译器会在成员之间加上填充字节。

(3) 结构体的总大小为 有效对齐值 的整数倍，
如有需要编译器会在最末一个成员之后加上填充字节。
*/

#if 0
int main(int argc, char* argv[])
{
	struct tagTest1
	{
		short a;
		char d;
		long b;
		long c;
	};
	struct tagTest2
	{
		long b;
		short c;
		char d;
		long a;
	};
	struct tagTest3
	{
		short c;
		long b;
		char d;
		long a;
	};
	struct tagTest1 stT1;
	struct tagTest2 stT2;
	struct tagTest3 stT3;

	printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3));
	return 0;
} // 12 12 16
#endif

#if 0
#define MAX_SIZE A+B
struct _Record_Struct
{
	unsigned char Env_Alarm_ID : 4;
	unsigned char Para1 : 2;
	unsigned char state;
	unsigned char avail : 1;
}*Env_Alarm_Record;

struct _Record_Struct* pointer = 
	(struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
#endif
//9

#if 0
int main()
{
	unsigned char puc[4];
	struct tagPIM
	{
		unsigned char ucPim1;
		unsigned char ucData0 : 1;
		unsigned char ucData1 : 2;
		unsigned char ucData2 : 3;
	}*pstPimData;
	pstPimData = (struct tagPIM*)puc;
	memset(puc, 0, 4);
	pstPimData->ucPim1 = 2;
	pstPimData->ucData0 = 3;
	pstPimData->ucData1 = 4;
	pstPimData->ucData2 = 5;
	printf("%02x %02x %02x %02x\n", puc[0], puc[1], puc[2], puc[3]);
	return 0;
}
#endif
// 02 29 00 00


//3839
#if 0
int main()
{
	union
	{
		short k;
		char i[2];
	}*s, a;
	s = &a;
	s->i[0] = 0x39;
	s->i[1] = 0x38;
	printf("%x\n", a.k);
	return 0;
}
#endif

//1 257
#if 0
enum ENUM_A
{
	X1,
	Y1,
	Z1 = 255,
	A1,
	B1,
};
int main() {
	enum ENUM_A enumA = Y1;
	enum ENUM_A enumB = B1;
	printf("%d %d\n", enumA, enumB);
}
#endif

















